package com.jinzhi.jinzhidata.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jinzhi.jinzhidata.util.JwtUtil;
import com.jinzhi.jinzhidata.dataobject.User;
import com.jinzhi.jinzhidata.dataobject.Wallet;
import com.jinzhi.jinzhidata.enums.ResultEnum;
import com.jinzhi.jinzhidata.pojo.WX.Config;
import com.jinzhi.jinzhidata.pojo.WX.Payment;
import com.jinzhi.jinzhidata.service.UserService;
import com.jinzhi.jinzhidata.service.WalletService;
import com.jinzhi.jinzhidata.util.*;
import com.jinzhi.jinzhidata.util.wxpay.*;
import com.jinzhi.jinzhidata.vo.ResultVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * @description
 * @date 2020-01-04 17:29
 **/
@RequestMapping("/wallet")
@RestController
public class WalletController {

    @Autowired
    WalletService walletService;

    @Autowired
    UserService userService;


    /**
     * 微信网页端积分充值
     *
     * @param amount
     * @param request
     * @param response
     * @return
     */
    @GetMapping(value = "/charge")
    @ResponseBody
    public ResultVO walletCharge(BigDecimal amount, HttpServletRequest request, HttpServletResponse response) {
        String userId = JwtUtil.verifyAccessToken(request, response);
        if (StringUtils.isEmpty(userId)) {
            return ResultVOUtil.error(ResultEnum.NOT_LOGIN);
        }
        // 实际充值金额
        Wallet wallet = new Wallet();
        wallet.setWalletId(UUIDUtil.getUUID());
        wallet.setWalletUserId(userId);
        wallet.setWalletAmount(amount);
        // 把流水操作类型设置为充值
        wallet.setWalletOperationType(Constant.WALLET_OPERATION_CHARGE);
        wallet.setWalletState("0");
        Map<String, String> data = new HashMap<>();
        data.put("body", "尽智研究院-影响100万交通企业");
        data.put("out_trade_no", WXPayUtil.generateNonceStr());
        data.put("device_info", "WEB");
        data.put("fee_type", "CNY");
        data.put("total_fee", String.valueOf(amount.multiply(new BigDecimal(100)).longValue()));  //单位为分
        data.put("spbill_create_ip", request.getRemoteAddr());
        data.put("notify_url", Constant.BASE_URL + "/v2/wallet/chargeCallback");
        data.put("trade_type", "JSAPI");
        data.put("attach", wallet.getWalletId());
        User user = userService.selectUserByUserId(userId);
        data.put("openid", user.getUserWechatId());
        // 设置tradeId
        wallet.setWalletTradeNo(data.get("out_trade_no"));
        try {
            System.out.println(JSON.toJSON(data));
            WXPayConfigImpl wxPayConfig = WXPayConfigImpl.getInstance();
            WXPay wxPay = new WXPay(wxPayConfig);
            Map<String, String> res = wxPay.unifiedOrder(data);
            System.out.println(JSON.toJSON(res));
            String returnCode = res.get("return_code");
            String resultCode = res.get("result_code");
            if (returnCode.equals(WXPayConstant.SUCCESS) && resultCode.equals(WXPayConstant.SUCCESS)) {
                Payment payment = new Payment();
                String prepay_Id = res.get("prepay_id");
                String nonce_str = res.get("nonce_str");
                Map<String, String> repay = new HashMap<>();
                repay.put("appId", Constant.WX_APPID);
                String timestamp = String.valueOf(WXPayUtil.getCurrentTimestamp());
                repay.put("timeStamp", timestamp);
                payment.setTimeStamp(timestamp);
                repay.put("nonceStr", nonce_str);
                payment.setNonceStr(nonce_str);
                repay.put("package", "prepay_id=" + prepay_Id);
                payment.set_package("prepay_id=" + prepay_Id);
                repay.put("signType", "MD5");
                payment.setSignType("MD5");
                String paySign = WXPayUtil.generateSignature(repay, Constant.WX_KEY);
                payment.setPaySign(paySign);
                String jsapi_ticket = WXHelper.getJsApiTicket();
                String url = Constant.BASE_URL + request.getRequestURI();
                String queryStr = request.getQueryString();
                if (queryStr != null) {
                    url = url + "?" + queryStr;
                }
                Map<String, String> conf = WXHelper.getJsApiConfig(url, jsapi_ticket, nonce_str, timestamp);
                Config config = new Config();
                config.setAppid(Constant.WX_APPID);
                config.setJsapi_ticket(jsapi_ticket);
                config.setNonceStr(nonce_str);
                config.setTimestamp(timestamp);
                config.setUrl(url);
                config.setSignature(conf.get("signature"));
                Wallet returnWallet = walletService.saveWallet(wallet);
                if (returnWallet == null) {
                    return ResultVOUtil.error(ResultEnum.CHARGE_ORDER_CREATE_FAILED);
                }
                Map<String, Object> responseData = new HashMap<>();
                responseData.put("config", config);
                responseData.put("payment", payment);
                return ResultVOUtil.success(responseData);
            } else {
                return ResultVOUtil.error(ResultEnum.CHARGE_ORDER_CREATE_FAILED);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return ResultVOUtil.error(ResultEnum.CHARGE_ORDER_CREATE_FAILED);
        }
    }


    /**
     * 微信网页端积分充值微信支付回调
     *
     * @param printWriter
     * @param inputStream
     * @return
     */
    @PostMapping(value = "/chargeCallback")
    public void chargeCallBack(PrintWriter printWriter, InputStream inputStream) {
        if (null == inputStream) {
            printWriter.write("<xml><return_code><![CDATA[FAIL]]></return_code></xml>");
            printWriter.close();
            return;
        }
        try {
            String resultStr;
            int buffer_size = 1024;
            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
            int count;
            byte[] tempBytes = new byte[buffer_size];
            while (true) {
                if ((count = inputStream.read(tempBytes, 0, buffer_size)) == -1) {
                    break;
                }
                outStream.write(tempBytes, 0, count);
            }
            outStream.flush();
            //将流转换成字符串
            resultStr = new String(outStream.toByteArray(), "UTF-8");
            //将XML格式转化成MAP格式数据
            Map<String, String> resultMap = WXPayUtil.xmlToMap(resultStr);
            boolean result = false;
            String returncode = resultMap.get("return_code");
            if (returncode != null && returncode.equals("SUCCESS")) {
                result = WXPayUtil.isSignatureValid(resultMap, Constant.WX_KEY, WXPayConstant.SignType.MD5);
            }
            if (result) {
                String walletId = resultMap.get("attach");
                Wallet wallet = walletService.selectByWalletId(walletId);
                wallet.setWalletTransactionId(resultMap.get("transaction_id"));
                wallet.setWalletPayType(resultMap.get("bank_type"));
                wallet.setWalletPay(new BigDecimal(resultMap.get("cash_fee")).multiply(new BigDecimal(100)));
                System.out.println("实际支付金额：" + new BigDecimal(resultMap.get("cash_fee")));
                // 把订单状态设置为已支付
                wallet.setWalletState("1");
                // 增加充值者余额
                String userId = wallet.getWalletUserId();
                Integer ret = userService.updateUserBalance(userId, wallet.getWalletAmount());
                if (ret == 0) {
                    printWriter.write("<xml><return_code><![CDATA[FAIL]]></return_code></xml>");
                    printWriter.close();
                    return;
                }
                Wallet returnWallet = walletService.saveWallet(wallet);
                if (returnWallet == null) {
                    printWriter.write("<xml><return_code><![CDATA[FAIL]]></return_code></xml>");
                    printWriter.close();
                    return;
                }
                printWriter.write("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
                printWriter.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
            printWriter.write("<xml><return_code><![CDATA[FAIL]]></return_code></xml>");
            printWriter.close();
        }
    }

    /**
     * 自动提现操作
     *
     * @param request
     * @param response
     * @param amount
     * @return
     */
    @GetMapping(value = "/withdraw")
    public ResultVO walletWithdraw(BigDecimal amount, HttpServletRequest request, HttpServletResponse response) {
        String userId = JwtUtil.verifyAccessToken(request, response);
        if (StringUtils.isEmpty(userId)) {
            return ResultVOUtil.error(ResultEnum.NOT_LOGIN);
        }
        // 实际提现金额
        System.out.println(amount);
        if (amount.compareTo(new BigDecimal(0.01)) < 0) {
            return ResultVOUtil.error(ResultEnum.WITHDRAW_AMOUNT_LOWER_THAN_ONE_ERROR);
        }
        User loginUser = userService.selectUserByUserId(userId);
        if (null == loginUser) {
            return ResultVOUtil.error(ResultEnum.NULL_ERROR.getCode(), "用户不存在");
        }
        if (loginUser.getUserBalance().compareTo(amount) < 0) {
            return ResultVOUtil.error(ResultEnum.WITHDRAW_AMOUNT_HIGHER_THAN_BALANCE_ERROR);
        }
        Wallet wallet = new Wallet();
        wallet.setWalletId(UUIDUtil.getUUID());
        wallet.setWalletAmount(amount);
        wallet.setWalletUserId(userId);
        wallet.setWalletTradeNo(UUIDUtil.getUUID());
        wallet.setWalletState("0");
        Map<String, String> data = new HashMap<>();
        data.put("mch_appid", Constant.WX_APPID);
        data.put("mchid", Constant.WX_MCH_ID);
        data.put("device_info", "WEB");
        data.put("nonce_str", WXPayUtil.generateNonceStr());
        data.put("partner_trade_no", wallet.getWalletTradeNo());
        data.put("openid", loginUser.getUserWechatId());
        data.put("check_name", "NO_CHECK");
        data.put("amount", String.valueOf(amount.multiply(new BigDecimal(100)).longValue()));
        data.put("desc", "提现");
        data.put("spbill_create_ip", request.getRemoteAddr());
        System.out.println(JSONObject.toJSONString(data));
        try {
            String sign = WXPayUtil.generateSignature(data, Constant.WX_KEY);
            data.put("sign", sign);
            String requestXml = WXPayUtil.mapToXml(data);
            WXPayConfigImpl wxPayConfig = WXPayConfigImpl.getInstance();
            WXPayRequest wxPayRequest = new WXPayRequest(wxPayConfig);
            String resultXml = wxPayRequest.requestWithCert("/mmpaymkttransfers/promotion/transfers", UUIDUtil.getUUID(), requestXml, false);
            Map<String, String> resultMap = WXPayUtil.xmlToMap(resultXml);
            System.out.println(JSONObject.toJSONString(resultMap));
            String returncode = resultMap.get("return_code");
            boolean result = false;
            if (returncode != null && returncode.equals("SUCCESS")) {
                result = WXPayUtil.isSignatureValid(resultMap, Constant.WX_KEY, WXPayConstant.SignType.MD5);
            }
            if (result) {
                userService.updateUserBalance(userId, amount.negate());
                wallet.setWalletState("1");
                Wallet ret = walletService.saveWallet(wallet);
                if (ret == null) {
                    return ResultVOUtil.error(ResultEnum.WITHDRAW_FAILED.getCode(), "更新用户余额失败");
                }
                return ResultVOUtil.success();
            } else {
                return ResultVOUtil.error(ResultEnum.WITHDRAW_FAILED);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return ResultVOUtil.error(ResultEnum.WITHDRAW_FAILED);
        }
    }


    /**
     * 网页端充值，返回移动端充值
     *
     * @param request
     * @param response
     * @return
     */
    @GetMapping(value = "/webCharge")
    @ResponseBody
    public ResultVO webWalletCharge(HttpServletRequest request, HttpServletResponse response) {
        String token = request.getHeader("accessToken");
        if (token == null) {
            token = CookieUtil.getCookieValue(request, "accessToken");
            if (token == null) {
                return ResultVOUtil.error(ResultEnum.NOT_LOGIN);
            }
        }
        String url = Constant.BASE_URL + "/v2/user_wallet.html?accessToken=" + token;
        try {
            JSONObject data = new JSONObject();
            data.put("qrCodeBase64", QRCodeUtil.createQRCode(url, 300, 300));
            return ResultVOUtil.success(data);
        } catch (Exception e) {
            e.printStackTrace();
            return ResultVOUtil.error(ResultEnum.WRONG);
        }
    }
}
